package com.bcx.wind.workflow.imp.cmd.corecmd;

import com.bcx.wind.workflow.access.QueryFilter;
import com.bcx.wind.workflow.core.constant.TaskLevel;
import com.bcx.wind.workflow.core.constant.TaskStatus;
import com.bcx.wind.workflow.core.constant.WorkflowOperate;
import com.bcx.wind.workflow.entity.WindOrder;
import com.bcx.wind.workflow.entity.WindProcess;
import com.bcx.wind.workflow.entity.WindProcessConfig;
import com.bcx.wind.workflow.entity.WindTask;
import com.bcx.wind.workflow.pojo.Wind;
import com.bcx.wind.workflow.pojo.WindUser;
import com.bcx.wind.workflow.pojo.variable.WithDrawVariable;
import com.bcx.wind.workflow.support.Assert;
import com.bcx.wind.workflow.support.ObjectHelper;

import java.util.List;
import java.util.stream.Collectors;

import static com.bcx.wind.workflow.access.AccessSqlConstant.ORDER_ID;
import static com.bcx.wind.workflow.core.constant.Constant.WIND_ADMIN;
import static com.bcx.wind.workflow.message.ErrorCode.*;


/**
 * <p>
 * 撤回命令
 * 和完结命令类似，不同的是撤回是将流程回退到最初的状态，保留历史履历，可再次审核。而完结是直接将流程执行完毕，保留履历，不可再次审核。
 *
 * 主要逻辑： 构建流程执行wind对象， 删除该流程下正在执行的所有任务，审批人，流程实例。  保存历史履历
 * </p>
 *
 * @author zhanglei
 * @since 2019-04-28 14:23:21
 */
public class WithDrawCommand extends BaseCommand {

    private WithDrawVariable  variable;

    public WithDrawCommand(WithDrawVariable variable){
        this.variable = variable;
    }
    @Override
    public Wind execute() {
        wind().setOperate(WorkflowOperate.withdraw);
        //校验参数
        checkVariable();
        //实例化执行wind
        initWind();
        //当前任务节点
        withdrawAndCompleteCurNode();
        //执行完结操作
        completeOperate();
        return wind();
    }



    private  void  completeOperate(){
        String orderId = wind().getWindOrder().getId();
        //删除所有流程实例
        this.commandContext.access().removeOrderInstanceById(orderId);
        this.commandContext.access().removeOrderInstanceByParentId(orderId);
        //删除所有任务实例，以及任务审批人
        List<WindTask> tasks = this.commandContext.access().selectTaskInstanceList(new QueryFilter().setOrderId(orderId));
        this.commandContext.access().removeTaskByOrderId(orderId);
        this.commandContext.access().removeTaskActorByTaskIds(tasks.stream().map(WindTask::getId).collect(Collectors.toList()));

        //删除撤销暂存数据
        this.commandContext.access().deleteWindRevokeDataByOrderId(orderId);
        //更新历史履历
        changeResume();
    }




    /**
     * 实例化执行数据集
     */
    private void initWind(){
        String orderId = this.variable.getOrderId();

        //流程实例
        WindOrder windOrder = buildWindOrder(orderId);

        //流程定义
        WindProcess windProcess = this.commandContext.repositoryService().queryById(windOrder.getProcessId());
        Assert.notEmptyError(WITH_DRAW_FAIL,windProcess,windOrder.getProcessId());

        //所有任务实例
        QueryFilter filter = new QueryFilter()
                .setOrderId(orderId)
                .setStatus(TaskStatus.run.name())
                .setTaskLevel(TaskLevel.main.name());
        List<WindTask> windTasks = this.commandContext.access().selectTaskInstanceList(filter);
        Assert.notEmptyError(NOT_FOUND_TASK,windTasks);
        //多个任务不可撤回
        Assert.isTrueError(WITH_DRAW_NOT_SUPPORT,windTasks.size() > 1);

        //所有配置
        getConfigList(windProcess.getId());

        wind().setWindOrder(windOrder)
                .setBusinessId(windOrder.getBusinessId())
                .setWindProcess(windProcess)
                .setUser(user())
                .setSystem(this.variable.getSystem())
                .setAllTasks(windTasks)
                .setSuggest(this.variable.getSuggest())
                .setArgs(this.variable.getArgs())
                .setWindConfig(buildWindConfig(buildProcessConfig()));
    }


    /**
     * 当前流程配置
     */
    private WindProcessConfig buildProcessConfig(){
        String processName = wind().getWindProcess().getProcessName();
        WindProcessConfig processConfig = ObjectHelper.getNodeConfig(this.configList,processName,this.variable.getArgs());
        Assert.notEmptyError(PROCESS_CONFIG_NOT_FOUND,processConfig,processName,processName);
        return processConfig;
    }




    /**
     * 校验完结参数
     */
    private void checkVariable(){
        String orderId = this.variable.getOrderId();
        Assert.notEmptyError(WITH_DRAW_FAIL,orderId,ORDER_ID);
    }


    /**
     * 当前用户  默认使用 wind_admin
     * @return  当前用户
     */
    private WindUser user(){
        WindUser user = this.variable.getUser();
        if(user == null){
            user = new WindUser()
                    .setUserId(WIND_ADMIN)
                    .setUserName("管理员");
        }
        return user;
    }
}
